package impl

import (
	"context"
	"fmt"
	"net/http"

	"gitee.com/go-course/go11/vblog/apps/user"
	"gitee.com/go-course/go11/vblog/common"
)

// 用户的创建
func (i *impl) CreateUser(ctx context.Context, in *user.CreateUserRequest) (
	*user.User, error) {
	if err := in.Validate(); err != nil {
		return nil, common.NewApiException(http.StatusBadRequest, err.Error())
	}

	// 使用构造函数来创建一个对象
	ins := user.NewUser(in)
	err := ins.BuildHashedPassword()
	if err != nil {
		return nil, err
	}

	err = i.db.WithContext(ctx).Save(ins).Error
	if err != nil {
		return nil, common.NewApiException(http.StatusInternalServerError, err.Error())
	}

	return ins, nil
}

// 查询用户详情
func (i *impl) DescribeUser(ctx context.Context, in *user.DescribeUserRequest) (
	*user.User, error) {
	//  需要构造SQL查询
	query := i.db.
		WithContext(ctx).
		Model(&user.User{})

		// 都是字符串
	switch in.DescribeBy {
	case user.DESCRIBE_BY_ID:
		// SELECT * FROM `users` WHERE id = '3' ORDER BY `users`.`id` LIMIT 1
		query = query.Where("id = ?", in.DescribeValue)
	case user.DESCRIBE_BY_NAME:
		// SELECT * FROM `users` WHERE username = 'admin' ORDER BY `users`.`id` LIMIT 1
		query = query.Where("username = ?", in.DescribeValue)
	default:
		return nil, fmt.Errorf("unknown describe by")
	}

	ins := user.NewDefaultUser()
	err := query.First(ins).Error
	if err != nil {
		return nil, err
	}

	return ins, nil
}

// 用户登录接口
func (i *impl) Login(ctx context.Context, in *user.LoginRequest) (
	*user.Token, error) {
	// 比对对用的用户名密码, 先要把用户对象查询出来
	u, err := i.DescribeUser(ctx, user.NewDescribeUserRequestByName(in.Username))
	if err != nil {
		return nil, err
	}

	// 密码校验
	err = u.CheckPassord(in.Password)
	if err != nil {
		return nil, common.NewApiException(
			http.StatusUnauthorized,
			"check passowrd error: "+err.Error(),
		)
	}

	// 颁发一个Token给用户
	tk := user.NewToken(in.Username)
	err = i.db.Save(tk).Error
	if err != nil {
		return nil, err
	}

	return tk, nil
}

// 校验用户Token
func (i *impl) ValiateToken(ctx context.Context, in *user.ValiateTokenRequest) (
	*user.Token, error) {
	// 构造一个数据结构, 用户接收数据库查询的结构
	tk := user.NewToken("")
	// 查询该Token是否是我们系统颁发
	err := i.db.
		WithContext(ctx).
		Model(&user.Token{}).
		Where("access_token = ?", in.AccessToken).
		First(tk).
		Error
	if err != nil {
		return nil, err
	}

	// tk.CheckExpired()
	return tk, nil
}
